use alloc::vec::Vec;

use crate::{
    ir::graph::Graph,
    pass::{
        constant_folding::ConstantFolding, dead_code_elimination::DeadCodeElimination, pass::Pass,
    },
};

pub struct PassPipeline<'a> {
    passes: Vec<&'a mut dyn Pass>,
    pub max_fixed_point_iters: usize,
}

impl<'a> PassPipeline<'a> {
    pub fn new() -> Self {
        Self {
            passes: Vec::new(),
            max_fixed_point_iters: 10,
        }
    }
    pub fn add(&mut self, pass: &'a mut dyn Pass) {
        self.passes.push(pass);
    }

    pub fn run(&mut self, graph: &mut Graph) -> bool {
        let mut changed_any = false;
        for _ in 0..self.max_fixed_point_iters {
            let mut changed = false;
            for pass in self.passes.iter_mut() {
                changed |= pass.run(graph).changed;
            }
            changed_any |= changed;
            if !changed {
                break;
            }
        }
        changed_any
    }
}

pub fn run_all_passes(graph: &mut Graph) -> bool {
    let mut constant_folding = ConstantFolding {};
    let mut dead_code_elimination = DeadCodeElimination {};
    let mut pipeline = PassPipeline::new();
    pipeline.add(&mut constant_folding);
    pipeline.add(&mut dead_code_elimination);
    pipeline.run(graph)
}
